package  main.java.leetcode.editor.cn;
//2022-04-06 16:05:55
//树是一个无向图，其中任何两个顶点只通过一条路径连接。 换句话说，一个任何没有简单环路的连通图都是一棵树。 
//
// 给你一棵包含 n 个节点的树，标记为 0 到 n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表（每一个边都是一对标签），其中
// edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间存在一条无向边。 
//
// 可选择树中任何一个节点作为根。当选择节点 x 作为根节点时，设结果树的高度为 h 。在所有可能的树中，具有最小高度的树（即，min(h)）被称为 最小高度
//树 。 
//
// 请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。 
//树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。
//
// 
//
// 示例 1： 
//
// 
//输入：n = 4, edges = [[1,0],[1,2],[1,3]]
//输出：[1]
//解释：如图所示，当根是标签为 1 的节点时，树的高度是 1 ，这是唯一的最小高度树。 
//
// 示例 2： 
//
// 
//输入：n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
//输出：[3,4]
// 
//
// 
//
// 
// 
//
// 提示： 
//
// 
// 1 <= n <= 2 * 104 
// edges.length == n - 1 
// 0 <= ai, bi < n 
// ai != bi 
// 所有 (ai, bi) 互不相同 
// 给定的输入 保证 是一棵树，并且 不会有重复的边 
// 
// Related Topics 深度优先搜索 广度优先搜索 图 拓扑排序 
// 👍 569 👎 0

import java.util.*;

class MinimumHeightTrees {
    public static void main(String[] args) {
        //创建该题目的对象方便调用
        Solution solution = new MinimumHeightTrees().new Solution();
    }
    //leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public List<Integer> findMinHeightTrees(int n, int[][] edges) {
        List<Integer> result = new ArrayList<>();
        if(n == 1){ //一个结点不成为树，无高度
            result.add(0);
            return result;
        }
        List<Integer>[] dist = new List[n];  //记录结点路径 进行动态规划
        for(int i = 0;i<n;i++){  //创建各个结点的dp路径数组
            dist[i] = new ArrayList<>();
        }
        for(int[] edge : edges){   //初始化dp数组
            dist[edge[0]].add(edge[1]);
            dist[edge[1]].add(edge[0]);
        }
        int[] parent = new int[n];  //记录每一个根结点的父亲结点
        Arrays.fill(parent,-1);  //初始化父亲结点数组
        int x = findLongDistNode(0,parent,dist);
        int y = findLongDistNode(x,parent,dist);
        List<Integer> path = new ArrayList<>(); // 记录x,y结点之间的路径
        parent[x] = -1;  //使用结束后父亲结点数组重新初始化
        while (y!=-1){
            path.add(y);
            y = parent[y];
        }
        int m = path.size();
        /*
        *   如果m为偶数,此时最小根结点为P(m/2)或者P(m/2+1)此时最小的高度为m/2
        *   如果m为奇数,此时最小高度树的根结点为P((m+1)/2)此时最小的高度为(m-1)/2
        * */
        if(m%2 == 0){
            result.add(path.get(m/2-1));
        }
        result.add(path.get(m/2));
        return result;
    }

    //使用BFS寻找当前传入结点的最远结点
    public int findLongDistNode(int u,int[] parent,List<Integer>[] dist){
        int n = dist.length;
        Queue<Integer> queue = new ArrayDeque<>();
        boolean[] visit = new boolean[n];
        queue.offer(u);
        visit[u] = true;
        int node = -1;
        while (!queue.isEmpty()){
            int cur = queue.poll();
            node = cur;
            for(int v : dist[cur]){
                if(!visit[v]){
                    visit[v] = true;
                    parent[v] = cur;
                    queue.offer(v);
                }
            }
        }
        return node;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

}
